home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d7
/
asycls10.arc
/
ASYNCH.CPP
next >
Wrap
C/C++ Source or Header
|
1991-04-28
|
14KB
|
399 lines
/////////////////////////////////////////////////////////////////////////////
//
// Asynchronous Class for C++
// Copyright (C) 1991 by Jui-Lin Hung and SPD!
//
// You may freely use or incorporate these routines into your own programs
// without royalty to me, as I believe this is beneficial to programmers.
// However, I would like to request that if you distribute the source code,
// you would include this header in the source file and not remove it.
// Of course, I would have no way of knowing, but I am appealing to your
// sense of good will and morality. Thank you, and I hope these routines
// are useful.
//
// April, 1991 - Version 1.0
//
/////////////////////////////////////////////////////////////////////////////
#include <dos.h>
#include "asynch.h" // Asynch class definitions
//-------------------------------------------------------------------------\\
_asynch_info _ainfo; // Global asynchronous info variable
//-------------------------------------------------------------------------\\
void far interrupt (*OldVect)(...);
void far interrupt asynch_irq(...)
// Asynchronous port interrupt handler. This is the new interrupt which
// we will swap with the old one to handle all asynchronous i/o
{
static int temp;
enable(); // enable interrupts
for (;;)
{
temp = inportb(_ainfo.base+IIR); // why interrupt was called
if (temp & 0x01) // Nothing else to do
{
outportb(ICR,EOI); // reset interrupt
return; // return to program
}
switch(temp)
{
case 0x00: // modem status changed
inportb(_ainfo.base+MSR); // read in useless char
break;
case 0x02: // Request To Send char
if (_ainfo.outhead != _ainfo.outtail) // there's a char to send
{
// send the character
outportb(_ainfo.base+TXR,_ainfo.outbuf[_ainfo.outhead++]);
// if at end of buffer, reset pointer
if (_ainfo.outhead == OBUF_LEN) _ainfo.outhead=0;
}
break;
case 0x04: // character ready to be read in
// read character into inbuffer
_ainfo.inbuf[_ainfo.inhead++] = inportb(_ainfo.base+RXR);
if (_ainfo.inhead == IBUF_LEN) // if at end of buffer
_ainfo.inhead=0; // reset pointer
break;
case 0x06: // line status has changed
inportb(_ainfo.base+LSR); // read in useless char
break;
}
}
}
void Asynch::asynchInit()
// Initializes variables, saves old interrupt vectors and sets the new
// interrupts. Initializes the asynchronous port too.
{
_ainfo.inhead=_ainfo.intail=0; // reset in buffer pointers
_ainfo.outhead=_ainfo.outtail=0; // reset out buffer pointers
_ainfo.flow = 0; // Default flow control is off
_ainfo.nohangup = 0; // hangup when done
OldVect = getvect(_ainfo.irq+MCI); // Save old interrupt vector
setvect(_ainfo.irq+MCI,asynch_irq); // Set up serial int handler
outportb(_ainfo.base+LCR, 0x03); // Turn DTR and RTS on
disable(); // disable ints during init
int temp = inportb(_ainfo.base+LSR); // read serial port line status
temp = inportb(_ainfo.base+RXR); // read char
temp = inportb(IMR); // get interrupt settings
temp = temp & ((IER<<_ainfo.irq)^0xff); // turn on serial interrupt
outportb(IMR, temp); // send out new int settings
outportb(_ainfo.base+IER, IER); // turn on all IRQ events
outportb(_ainfo.base+MCR, inportb(_ainfo.base+MCR) | 0x0a);
enable(); // re-enable all interrupts
}
Asynch::Asynch(unsigned char p)
// Class constructor - set base address and irq number.
{
switch(p) // set up correct base address and irq for this port
{
case COM1: // serial port 1
_ainfo.base = 0x03f8; // base address for port 1
_ainfo.irq = 4; // interrupt number for port 1
break;
case COM2: // serial port 2
_ainfo.base = 0x02f8; // base address for port 2
_ainfo.irq = 3; // interrupt number for port 2
break;
case COM3: // serial port 3
_ainfo.base = 0x03e8; // base address for port 3
_ainfo.irq = 4; // interrupt number for port 3
break;
case COM4: // serial port 4
_ainfo.base = 0x02e8; // base address for port 4
_ainfo.irq = 3; // interrupt number for port 4
break;
default: // defaults to com2
_ainfo.base = 0x02f8; // base address for port 2
_ainfo.irq = 3; // interrupt number for port 2
break;
}
_ainfo.baud = 2400; // Default baud rate is 2400
asynchInit(); // call interrupt initialization
setBaud(_ainfo.baud); // set to default baud rate
}
Asynch::Asynch(unsigned char p,unsigned int b)
// Class constructor - set base address and irq number.
// This particular constructor also sets the baud rate to the
// specified speed
{
switch(p) // set up correct base address and irq for this port
{
case COM1: // serial port 1
_ainfo.base = 0x03f8; // base address for port 1
_ainfo.irq = 4; // interrupt number for port 1
break;
case COM2: // serial port 2
_ainfo.base = 0x02f8; // base address for port 2
_ainfo.irq = 3; // interrupt number for port 2
break;
case COM3: // serial port 3
_ainfo.base = 0x03e8; // base address for port 3
_ainfo.irq = 4; // interrupt number for port 3
break;
case COM4: // serial port 4
_ainfo.base = 0x02e8; // base address for port 4
_ainfo.irq = 3; // interrupt number for port 4
break;
default: // defaults to com2
_ainfo.base = 0x02f8; // base address for port 2
_ainfo.irq = 3; // interrupt number for port 2
break;
}
_ainfo.baud = b; // Default baud rate is 2400
asynchInit(); // call interrupt initialization
setBaud(_ainfo.baud); // set to default baud rate
}
Asynch::~Asynch()
// Class destructor - de-initializes the asynchronous port, and restores
// the old interrupts
{
disable(); // disable interrupts
int temp = inportb(IMR);
temp = temp | (IER << _ainfo.irq);
outportb(IMR, temp | CTS);
outportb(_ainfo.base+IIR, 0x00);
outportb(_ainfo.base+MCR, IER);
enable(); // enable interrupts
setvect(_ainfo.irq+MCI,OldVect); // reinstate old vector
}
void Asynch::setBaud(unsigned int b)
// Sets the baud rate to the specified speed
{
if (b > 49 && (long)b < 57601L)
{
float rate = 115200.0 / ((float)b);
_ainfo.baud = (unsigned int)rate;
outportb(_ainfo.base+LCR, inportb(_ainfo.base+LCR) | 0x80);
outportb(_ainfo.base, (_ainfo.baud & 0x00ff));
outportb(_ainfo.base+IER, ((_ainfo.baud >> MCI) & 0x00ff));
outportb(_ainfo.base+LCR, inportb(_ainfo.base+LCR) & 0x7f);
}
}
int Asynch::dtr()
// Returns 1 if the DTR is high, or if DTR remains low, returns a 0
{
int addr;
switch(_ainfo.port)
{
case COM1: addr = 0x03fe; break;
case COM2: addr = 0x02fe; break;
case COM3: addr = 0x03ee; break;
case COM4: addr = 0x02ee; break;
}
if (inportb(addr) & 128)
return(1);
delay(500);
return(inportb(addr) & 128);
}
void Asynch::setDtr()
// This function basically sets the DTR to high.
{
outportb(_ainfo.base+MCR, inportb(_ainfo.base+MCR) & 0x00fe);
}
void Asynch::dropDtr()
// This function basically sets the DTR to low (i.e. hangs up the phone)
{
int addr;
if (!_ainfo.nohangup)
{
switch(_ainfo.port)
{
case COM1: addr = 0x03fc; break;
case COM2: addr = 0x02fc; break;
case COM3: addr = 0x03ec; break;
case COM4: addr = 0x02ec; break;
}
outportb(addr, inportb(addr) & 0xfe);
delay(500);
}
}
int Asynch::inCount()
// Counts how many characters are remaining to be read in from the input
// buffer
{
int len = _ainfo.intail - _ainfo.inhead;
return((len>0) ? len:(-len));
}
int Asynch::outCount()
// Counts how many characters are remaining to be outputted in the output
// buffer
{
int len = _ainfo.outtail - _ainfo.outhead;
return((len>0) ? len:(-len));
}
void Asynch::flushInBuf()
// Flushes the input buffer
{
disable(); // disable interrupts
_ainfo.inhead=_ainfo.intail=0; // reset pointers (dump buffer)
enable(); // enable interrupts
}
void Asynch::flushOutBuf()
// Flushes the output buffer
{
disable(); // disable interrupts
_ainfo.outhead=_ainfo.outtail=0; // reset pointers (dump buffer)
enable(); // enable interrupts
}
Asynch &Asynch::operator<<(char ch)
// Inserts the character to be outputted into the output buffer, checking
// for an open slot in the output buffer array. If there is, insert
// the character, or if there isn't, wait until a slot opens up.
{
if (ch) // If this is a valid char
{
enable(); // turn on irqs to ensure data output
// check buffer, and if full, wait for an available opening
while((_ainfo.outhead-1==_ainfo.outtail) ||
(_ainfo.outtail==OBUF_LEN-1 && _ainfo.outhead==0))
;
disable(); // make sure nothing happens while changing buffer
_ainfo.outbuf[_ainfo.outtail++]=ch; // insert character into buffer;
if (_ainfo.outtail == OBUF_LEN) // if at end of out buffer
_ainfo.outtail = 0; // reset pointer
enable(); // re-enable interrupts
outportb(_ainfo.base+DTR,0x0f);
}
return(*this);
}
Asynch &Asynch::operator<<(char *str)
// Outputs a string to the serial port
{
while (*str)
{
if (*str=='\n')
(*this) << '\r', (*this) << '\n';
else
(*this) << (*str);
str++;
}
return(*this);
}
Asynch &Asynch::operator>>(char &ch)
// Returns either the character to be received from modem if there is one
// waiting in the buffer, or returns a 0 if there is no character waiting.
{
if (_ainfo.inhead != _ainfo.intail) // there is a character
{
disable(); // disable irqs while getting char
ch = _ainfo.inbuf[_ainfo.intail++]; // get character from buffer
if (_ainfo.intail == IBUF_LEN) // if at end of in buffer
_ainfo.intail=0; // reset pointer
enable(); // re-enable interrupt
return(*this); // return the char
}
ch = 0;
return(*this); // return nothing
}
// C type functions for asynchronous i/o
void Asynch::outCh(char ch)
// Inserts the character to be outputted into output buffer. If there is
// an open slot in the output buffer array, insert character there, or
// wait for a slot to open.
{
if (ch) // If this is a valid char
{
enable(); // turn on irqs to ensure data output
// check buffer, and if full, wait for an available opening
while((_ainfo.outhead-1==_ainfo.outtail) ||
(_ainfo.outtail==OBUF_LEN-1 && _ainfo.outhead==0))
;
disable(); // make sure nothing happens while changing buffer
_ainfo.outbuf[_ainfo.outtail++]=ch; // insert character into buffer;
if (_ainfo.outtail == OBUF_LEN) // if at end of out buffer
_ainfo.outtail = 0; // reset pointer
enable(); // re-enable interrupts
outportb(_ainfo.base+DTR,0x0f);
}
}
void Asynch::outStr(char *str)
// Outputs a string through the serial port
{
while (*str)
{
if (*str=='\n')
outCh('\r'), outCh('\n');
else
outCh(*str);
str++;
}
}
char inCh()
// Returns 0 if no character waiting, or the character itself if there
// is a character waiting in the buffer
{
if (_ainfo.inhead != _ainfo.intail) // there is a character
{
disable(); // disable irqs while getting char
// get character from buffer
unsigned char ch = _ainfo.inbuf[_ainfo.intail++];
if (_ainfo.intail == IBUF_LEN) // if at end of in buffer
_ainfo.intail=0; // reset pointer
enable(); // re-enable interrupt
return(ch); // return the char
}
return(0); // return nothing
}